package com.roads.site.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.roads.common.constant.ResultConstants;
import com.roads.common.utils.DateUtils;
import com.roads.common.utils.file.FileUtils;
import com.roads.site.domain.card.CardBackModel;
import com.roads.site.domain.card.CardFrontModel;
import com.roads.site.domain.card.CardModel;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @ClassName CardUtils
 * @Description 身份证工具类
 * @Author nhp
 * @Date 2022/10/30 0008 13:22
 **/
public class CardUtils {

    public static final int FILE_MAX_SIZE = 2 * 1024 * 1024;

    public static boolean is18CardNo(String cardNo) {
        Pattern pattern = Pattern.compile("^(\\d{6})(19|20)(\\d{2})(1[0-2]|0[1-9])(0[1-9]|[1-2][0-9]|3[0-1])(\\d{3})(\\d|X|x)?$");
        Matcher matcher = pattern.matcher(cardNo);
        int[] prefix = new int[]{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
        int[] suffix = new int[]{1, 0, 10, 9, 8, 7, 6, 5, 4, 3, 2};
        if (matcher.matches()) {
            Map<String, String> cityMap = initCityMap();
            if(cityMap.get(cardNo.substring(0,2)) == null ){
                return false;
            }
            //用来保存前17位各自乖以加权因子后的总和
            int cardNoWiSum = 0;
            for(int i = 0;i < 17;i++){
                cardNoWiSum += Integer.valueOf(cardNo.substring(i, i + 1)) * prefix[i];
            }
            //计算出校验码所在数组的位置
            int cardNoMod = cardNoWiSum % 11;
            //得到最后一位身份证号码
            String cardNoLast = cardNo.substring(17);
            //如果等于2，则说明校验码是10，身份证号码最后一位应该是X
            if(cardNoMod == 2){
                if(cardNoLast.equalsIgnoreCase("x")){
                    return true;
                }else{
                    return false;
                }
            }else{
                //用计算出的验证码与最后一位身份证号码匹配，如果一致，说明通过，否则是无效的身份证号码
                if(cardNoLast.equals(suffix[cardNoMod]+"")){
                    return true;
                }else{
                    return false;
                }
            }
        }
        return false;
    }

    /**
     * 身份证判断性别
     * 0：男 1：女
     * @param idNo 身份证号
     * @return 性别
     */
    public static String judgeGender(String idNo) {
        int gender = 0;
        char c = idNo.charAt(idNo.length() - 2);
        gender = Integer.parseInt(String.valueOf(c));
        if(gender % 2 == 1){
            return "1";
        }else{
            return "2";
        }
    }

    /**
     * 身份证计算年龄
     *
     * @param idNo 身份证号
     * @return 年龄
     */
    public static int countAge(String idNo) {
        // 年、月、日
        String year = idNo.substring(6).substring(0, 4);
        String month = idNo.substring(10).substring(0, 2);
        String day = idNo.substring(12).substring(0,2);
        Date date = new Date();// 得到当前的系统时间
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        // 当前年份
        String currentYear = format.format(date).substring(0, 4);
        // 月份
        String currentMonth = format.format(date).substring(5, 7);
        String currentDay = format.format(date).substring(8,10);//
        int age = 0;
        //如果月份相同
        if(Integer.parseInt(month) == Integer.parseInt(currentMonth)){
            //说明已经过了生日或者今天是生日
            if (Integer.parseInt(day) <= Integer.parseInt(currentDay)) {
                age = Integer.parseInt(currentYear) - Integer.parseInt(year);
            } else {
                age = Integer.parseInt(currentYear) - Integer.parseInt(year) - 1;
            }
        }else{
            if(Integer.parseInt(month) < Integer.parseInt(currentMonth)){
                //如果当前月份大于出生月份
                age = Integer.parseInt(currentYear) - Integer.parseInt(year);
            }else{
                //如果当前月份小于出生月份,说明生日还没过
                age = Integer.parseInt(currentYear) - Integer.parseInt(year) - 1;
            }
        }
        return age;
    }

    /**
     * 身份证提取生日
     *
     * @param idNo 身份证号
     * @return 生日
     */
    public static Date extractBirth(String idNo) {
        // 年、月、日
        String year = idNo.substring(6).substring(0, 4);
        String month = idNo.substring(10).substring(0, 2);
        String day = idNo.substring(12).substring(0,2);
        String birthday = year + "-" + month + "-" + day;
        return DateUtils.dateTime(DateUtils.YYYY_MM_DD, birthday);
    }

    private static Map<String, String> initCityMap() {
        Map<String, String> cityMap = new HashMap<String, String>();
        cityMap.put("11", "北京");
        cityMap.put("12", "天津");
        cityMap.put("13", "河北");
        cityMap.put("14", "山西");
        cityMap.put("15", "内蒙古");

        cityMap.put("21", "辽宁");
        cityMap.put("22", "吉林");
        cityMap.put("23", "黑龙江");

        cityMap.put("31", "上海");
        cityMap.put("32", "江苏");
        cityMap.put("33", "浙江");
        cityMap.put("34", "安徽");
        cityMap.put("35", "福建");
        cityMap.put("36", "江西");
        cityMap.put("37", "山东");

        cityMap.put("41", "河南");
        cityMap.put("42", "湖北");
        cityMap.put("43", "湖南");
        cityMap.put("44", "广东");
        cityMap.put("45", "广西");
        cityMap.put("46", "海南");

        cityMap.put("50", "重庆");
        cityMap.put("51", "四川");
        cityMap.put("52", "贵州");
        cityMap.put("53", "云南");
        cityMap.put("54", "西藏");

        cityMap.put("61", "陕西");
        cityMap.put("62", "甘肃");
        cityMap.put("63", "青海");
        cityMap.put("64", "宁夏");
        cityMap.put("65", "新疆");

        cityMap.put("71", "台湾");
        cityMap.put("81", "香港");
        cityMap.put("82", "澳门");
        cityMap.put("91", "国外");
        return cityMap;
    }

    public static CardModel cardUpload(String token, MultipartFile frontFile, MultipartFile backFile) throws Exception {
        byte[] frontBytes = frontFile.getBytes();
        byte[] backBytes = backFile.getBytes();
        return cardUpload(token, frontBytes, backBytes);
    }

    public static CardModel cardUpload(String token, File frontFile, File backFile) throws Exception {
        byte[] frontBytes = FileUtils.file2byte(frontFile);
        byte[] backBytes = FileUtils.file2byte(backFile);
        return cardUpload(token, frontBytes, backBytes);
    }


    public static CardModel cardUpload(String token, byte[] frontBytes, byte[] backBytes) throws Exception {
        CardModel cardModel = new CardModel();
        String frontResult = BaiduHttpUtils.idCardFront(token, frontBytes, "true");
        String backResult = BaiduHttpUtils.idCardBank(token, backBytes);
        JSONObject frontJsonObject = JSON.parseObject(frontResult);
        JSONObject backJsonObject = JSON.parseObject(backResult);
        String frontImageStatus = frontJsonObject.getString("image_status");
        String backImageStatus = backJsonObject.getString("image_status");
        if ("reversed_side".equals(frontImageStatus) || "reversed_side".equals(backImageStatus)) {
            cardModel.setStatus(ResultConstants.RESULT_ERROR);
            cardModel.setContent("身份证正反面颠倒");
        } else if ("non_idcard".equals(frontImageStatus) || "non_idcard".equals(backImageStatus)) {
            cardModel.setStatus(ResultConstants.RESULT_ERROR);
            cardModel.setContent("上传的图片中不包含身份证");
        } else if ("blurred".equals(frontImageStatus) || "blurred".equals(backImageStatus)) {
            cardModel.setStatus(ResultConstants.RESULT_ERROR);
            cardModel.setContent("身份证模糊");
        } else if ("over_exposure".equals(frontImageStatus) || "over_exposure".equals(backImageStatus)) {
            cardModel.setStatus(ResultConstants.RESULT_ERROR);
            cardModel.setContent("身份证关键字段反光或过曝");
        } else if ("other_type_card".equals(frontImageStatus) || "other_type_card".equals(backImageStatus)) {
            cardModel.setStatus(ResultConstants.RESULT_ERROR);
            cardModel.setContent("其他类型证照");
        } else if ("over_dark".equals(frontImageStatus) || "over_dark".equals(backImageStatus)) {
            cardModel.setStatus(ResultConstants.RESULT_ERROR);
            cardModel.setContent("身份证欠曝（亮度过低）");
        } else if ("unknown".equals(frontImageStatus) || "unknown".equals(backImageStatus)) {
            cardModel.setStatus(ResultConstants.RESULT_ERROR);
            cardModel.setContent("未知状态");
        }
        if (!ResultConstants.RESULT_ERROR.equals(cardModel.getStatus())) {
            CardFrontModel cardFront = parseCardFrontModel(frontJsonObject);
            cardFront.setBytes(frontBytes);
            CardBackModel cardBack = parseCardBackModel(backJsonObject);
            cardBack.setBytes(backBytes);
            cardModel.setIdNo(cardFront.getIdNo());
            cardModel.setCardFront(cardFront);
            cardModel.setCardBack(cardBack);
            cardModel.setStatus(ResultConstants.RESULT_SUCCESS);
        }
        return cardModel;
    }

    /**
     * 百度结果身份证正面转实体
     *
     * @param json 身份证正面json
     * @return 身份证正面实体
     */
    public static CardFrontModel parseCardFrontModel(JSONObject json) {
        CardFrontModel front = new CardFrontModel();
        front.setPhoto(json.getString("photo"));
        JSONObject wordsResult = json.getJSONObject("words_result");
        front.setIdNo(wordsResult.getJSONObject("公民身份号码").getString("words"));
        front.setName(wordsResult.getJSONObject("姓名").getString("words"));
        front.setBirthday(wordsResult.getJSONObject("出生").getString("words"));
        front.setNation(wordsResult.getJSONObject("民族").getString("words") + "族");
        front.setSex(wordsResult.getJSONObject("性别").getString("words").equals("男") ? "1" : "2");
        front.setAddress(wordsResult.getJSONObject("住址").getString("words"));
        return front;
    }

    /**
     * 百度结果身份证背面转实体
     *
     * @param json 身份证背面json
     * @return 身份证背面实体
     */
    public static CardBackModel parseCardBackModel(JSONObject json) {
        CardBackModel back = new CardBackModel();
        JSONObject wordsResult = json.getJSONObject("words_result");
        back.setBeginDate(wordsResult.getJSONObject("签发日期").getString("words"));
        back.setEndDate(wordsResult.getJSONObject("失效日期").getString("words"));
        back.setSigningOrg(wordsResult.getJSONObject("签发机关").getString("words"));
        return back;
    }

}
